﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;



namespace EpisodeWizard.Core
{

	static class FileIdentification
	{

		public class WeightedGuess<T>
		{
			public WeightedGuess(T _Value)
			{
				Value = _Value;
				Weight = 1;
			}
			public T Value;
			public int Weight;
		}


		/// <summary>
		/// A list of words commonly found in file name
		/// That are not of any use
		/// </summary>
		static string IgnoreList = "season;hdtv;xvid;lol;dvd;hd;tv;dot;rip";



		/// <summary>
		/// Identifies a list of possible shows
		/// </summary>
		public static List<WeightedGuess<FuzzyString>> IdentifyShow(EpisodeFile EF)
		{
			List<WeightedGuess<FuzzyString>> ShowGuesses = new List<WeightedGuess<FuzzyString>>();
			string NameRegex = "(?<show>[a-zA-Z][a-zA-Z\\-\\.' &]{2,70}[a-zA-Z])";
			Regex R = null;
			Match m = null;

			// Use the file name
			string Filename = System.IO.Path.GetFileNameWithoutExtension(EF.Filepath);
			R = new Regex(NameRegex);
			m = R.Match(Filename);
			while (m.Success)
			{
				Group GS = m.Groups["show"];
				AddShowGuess(ShowGuesses, GS.Captures[0].Value);
				m = m.NextMatch();
			}

			// Use the file path
			string Path = System.IO.Path.GetDirectoryName(EF.Filepath);
			R = new Regex(NameRegex);
			m = R.Match(Path);
			while (m.Success)
			{
				Group GS = m.Groups["show"];
				string ShowName = GS.Captures[0].Value;
				AddShowGuess(ShowGuesses, ShowName);

				m = m.NextMatch();
			}

			return ShowGuesses;
		}


		/// <summary>
		/// Add a show as a possible guess
		/// Increment its weight if it's already in the list
		/// </summary>
		private static void AddShowGuess(List<WeightedGuess<FuzzyString>> ShowGuesses, string ShowName)
		{
			if (IgnoreList.IndexOf(ShowName) == -1)
			{
				FuzzyString FuzzyShowName = new FuzzyString(ShowName);
				foreach (WeightedGuess<FuzzyString> ExistingGuess in ShowGuesses)
				{
					if (ExistingGuess.Value.Compare(FuzzyShowName) >= (int)FuzzyString.Resemblance.Similar)
					{
						++ExistingGuess.Weight;
						return;
					}
				}
				ShowGuesses.Add(new WeightedGuess<FuzzyString>(FuzzyShowName));
			}
		}


		/// <summary>
		/// Identifies a list of possible seasons and episode numbers
		/// </summary>
		public static List<EpisodeNumber> IdentifyEpisode(EpisodeFile EF)
		{
			List<EpisodeNumber> EpisodeGuesses = new List<EpisodeNumber>();

			string Filename = System.IO.Path.GetFileNameWithoutExtension(EF.Filepath);

			Regex R = null;
			Match m = null;

			// When season and episode are apart
			string Season = "(?<season>\\d{1,2})";
			string Episode = "(?<episode>\\d{1,2})";
			string Regex2 = "[sS.]?" + Season + "[exEX.]" + Episode;
			R = new Regex(Regex2);
			m = R.Match(Filename);
			while (m.Success)
			{
				Group GS = m.Groups["season"];
				Group GE = m.Groups["episode"];
				int SeasonNo = Convert.ToInt32(GS.Captures[0].Value);
				int EpisodeNo = Convert.ToInt32(GE.Captures[0].Value);
				AddEpisodeGuess(EpisodeGuesses, new EpisodeNumber(SeasonNo, EpisodeNo));
				m = m.NextMatch();
			}


			// When they form one big number
			string SeasonEpisode = "(?<seasonepisode>\\d{3,5})";
			string Regex3 = "s?" + SeasonEpisode;
			R = new Regex(Regex3);
			m = R.Match(Filename);
			while (m.Success)
			{
				Group GSE = m.Groups["seasonepisode"];
				string FullStr = GSE.Captures[0].Value;
				if (FullStr.Length == 3)
				{
					int SeasonNo = Convert.ToInt32(FullStr.Substring(0, 1));
					int EpisodeNo = Convert.ToInt32(FullStr.Substring(1, 2));
					AddEpisodeGuess(EpisodeGuesses, new EpisodeNumber(SeasonNo, EpisodeNo));
				}
				else if (FullStr.Length == 4)
				{
					int SeasonNo = Convert.ToInt32(FullStr.Substring(0, 2));
					int EpisodeNo = Convert.ToInt32(FullStr.Substring(2, 2));
					AddEpisodeGuess(EpisodeGuesses, new EpisodeNumber(SeasonNo, EpisodeNo));
				}
				m = m.NextMatch();
			}

			return EpisodeGuesses;
		}


		/// <summary>
		/// Add an episode number as a possible guess only if the list does not already contain this episode number
		/// </summary>
		private static void AddEpisodeGuess(List<EpisodeNumber> EpisodeGuesses, EpisodeNumber Info)
		{
			foreach (EpisodeNumber EI in EpisodeGuesses)
			{
				if (EI.Episode == Info.Episode && EI.Season == Info.Season)
				{
					return;
				}
			}
			EpisodeGuesses.Add(Info);
		}

	}
}
